package org.hcyspartnoc.demo;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.hcyspartnoc.demo.common.core.annotation.PreAuthorize;
import org.hcyspartnoc.demo.common.core.configuration.ContrapsychConfiguration;
import org.hcyspartnoc.demo.mapper.system.SysPermissionMapper;
import org.hcyspartnoc.demo.mapper.system.SysRoleMapper;
import org.hcyspartnoc.demo.mapper.system.SysRolePermissionMapper;
import org.hcyspartnoc.demo.mapper.system.SysRoleUserMapper;
import org.hcyspartnoc.demo.pojo.po.system.SysPermissionPo;
import org.hcyspartnoc.demo.pojo.po.system.SysRolePermissionPo;
import org.hcyspartnoc.demo.pojo.po.system.SysRolePo;
import org.hcyspartnoc.demo.pojo.po.system.SysRoleUserPo;
import org.hcyspartnoc.demo.utils.redis.RedisComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Objects;


@Component
public class StartupRunner implements ApplicationListener<ApplicationReadyEvent> {
    private static final Logger LOGGER = LoggerFactory.getLogger(StartupRunner.class);
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private SysPermissionMapper sysPermissionMapper;
    @Resource
    private SysRolePermissionMapper sysRolePermissionMapper;
    @Resource
    private WebApplicationContext applicationContext;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysRoleUserMapper sysRoleUserMapper;
    @Resource
    private ContrapsychConfiguration contrapsychConfiguration;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        scanRestController();
        loadAuthRelation();
    }

    /**
     * 扫描所有RestController注解修饰的控制器类
     */
    public void scanRestController() {
        ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            // 检查Bean是否带有@Controller注解
            if (beanDefinition.isSingleton() && Objects.equals(beanDefinition.getScope(), "singleton")) {
                try {
                    Class<?> beanClass = Class.forName(beanDefinition.getBeanClassName());
                    // 检查类是否带有@Controller注解
                    if (beanClass.isAnnotationPresent(Controller.class) || beanClass.isAnnotationPresent(RestController.class)) {
                        Method[] methods = beanClass.getDeclaredMethods();
                        loadPermissionToSQL(methods);
                        LOGGER.info("========================权限代码成功加载至数据库========================");
//                        String controllerPrefix = "";
//                        if (beanClass.isAnnotationPresent(RequestMapping.class)) {
//                            controllerPrefix = beanClass.getAnnotation(RequestMapping.class).value()[0];
//                            loadAllRequestURI(controllerPrefix, methods);
//                        }
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 加载权限到数据库
     *
     * @param methods controller对应的方法
     */
    public void loadPermissionToSQL(Method[] methods) {
        for (Method method : methods) {
            if (method.isAnnotationPresent(PreAuthorize.class)) {
                PreAuthorize annotation = method.getAnnotation(PreAuthorize.class);
                try {
                    sysPermissionMapper.insert(new SysPermissionPo(annotation.auth(), annotation.descr()));
                } catch (Exception ignored) {
                }
            }
        }
    }

    public void loadAuthRelation() {
        // 加载角色信息到redis
        for (SysRolePo rolePo : sysRoleMapper.selectList(new LambdaQueryWrapper<>())) {
            redisComponent.setRole(rolePo.getId(), rolePo.getStatus());
        }
        // 加载权限信息到redis
        for (SysPermissionPo permissionPo : sysPermissionMapper.selectList(new LambdaQueryWrapper<>())) {
            redisComponent.setPermission(permissionPo.getAuthCode(), permissionPo.getStatus());
        }
        // 加载角色&用户对应关系到redis
        for (SysRoleUserPo relation : sysRoleUserMapper.selectList(new LambdaQueryWrapper<>())) {
            redisComponent.setRU_Relation(relation.getUserId(), relation.getRoleId());
        }
        // 加载角色&权限对应关系到redis
        MPJLambdaWrapper<SysRolePermissionPo> wrapper = new MPJLambdaWrapper<SysRolePermissionPo>()
                .leftJoin(SysPermissionPo.class, SysPermissionPo::getId, SysRolePermissionPo::getPermissionId)
                .selectAll(SysRolePermissionPo.class)
                .selectAs(SysPermissionPo::getAuthCode, SysRolePermissionPo::getAuthCode)
                .selectAs(SysPermissionPo::getStatus, SysRolePermissionPo::getStatus);
        for (SysRolePermissionPo relation : sysRolePermissionMapper.selectJoinList(SysRolePermissionPo.class, wrapper)) {
            redisComponent.setRP_Relation(relation.getRoleId(), relation.getAuthCode(), relation.getPermissionId());
        }
        LOGGER.info("========================权限关系成功加载至数据库========================");
    }
//
//    /**
//     * 加载所有请求路径
//     * @param controllerPrefix controller请求前缀
//     * @param methods 方法
//     */
//    public void loadAllRequestURI(String controllerPrefix, Method[] methods) {
//        for (Method method : methods) {
//            for (Annotation annotation : method.getDeclaredAnnotations()) {
//                if (annotation.annotationType().isAnnotationPresent(RequestMapping.class)){
//                    String url = null;
//                    if (annotation instanceof GetMapping getMapping)
//                        url =getMapping.value()[0];
//                    else if(annotation instanceof PostMapping postMapping)
//                        url =postMapping.value()[0];
//                    else if(annotation instanceof PutMapping putMapping)
//                        url =putMapping.value()[0];
//                    else if(annotation instanceof DeleteMapping deleteMapping)
//                        url =deleteMapping.value()[0];
//                    if (Objects.isNull(url))continue;
//                    SystemConfiguration.allRequestURI.add(systemConfiguration.getContextPath()+controllerPrefix+url);
//                }
//            }
//        }
//    }
}